﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GameProtocol;
using System.Collections.Concurrent;
using YServer;
using GameProtocol.DTO;
using ServerApp.Cache;

namespace ServerApp.Logic
{
    public class MatchHandler:AbsMutiplitySendHandler,IMessageReceive
    {
        RoleCache rcache = CacheFactory.roleCache;

        /// <summary>
        /// 房间id映射表（线程安全字典）
        /// </summary>
        ConcurrentDictionary<int, MatchRoom> matchRoom = new ConcurrentDictionary<int, MatchRoom>();

        Dictionary<YToken, MatchRoom> tokenRoom = new Dictionary<YToken, MatchRoom>();

        /// <summary>
        /// 房间池（线程安全堆栈）
        /// </summary>
        ConcurrentStack<MatchRoom> roomStack = new ConcurrentStack<MatchRoom>();

        /// <summary>
        /// 房间id自增（线程安全）
        /// </summary>
        ConcurrentInt roomIndex = new ConcurrentInt();


        public MatchHandler() {
            SetProType();
        }

        public override void SetProType()
        {
            type = TypeProtocol.Match;
        }

        public void OnClientConn(YServer.YToken token)
        {
            
        }

        public void OnMessageReceive(YServer.YToken token, YServer.SocketModel model)
        {
            switch (model.command)
            {
                case MatchProtocol.ReFresh_CREQ:
                    ReFresh(token);
                    break;
                case MatchProtocol.Enter_CREQ:
                    Enter(token, model);
                    break;
                case MatchProtocol.Create_CREQ:
                    Create(token);
                    break;
                case MatchProtocol.Change_CREQ:
                    Change(token);
                    break;
                case MatchProtocol.Leave_CREQ:
                    Console.WriteLine("leave");
                    Leave(token);
                    break;
                case MatchProtocol.Start_CREQ:
                    Start(token, model);
                    break;
                case MatchProtocol.Chat_CREQ:
                    Chat(token, model);
                    break;
                default:
                    break;
            }
        }

        void ReFresh(YToken token) {
            List<MatchRoomDTO> roomlist = new List<MatchRoomDTO>();
            //获取id映射表中的值
            foreach (MatchRoom item in matchRoom.Values)
            {
                MatchRoomDTO dto = new MatchRoomDTO(item.id, item.role_name);
                roomlist.Add(dto);
            }
            //发送dto列表
            Console.WriteLine("refresh");
            MatchRoomDTO[] rooms = roomlist.ToArray();
            Send(token, TypeProtocol.Match, 0, MatchProtocol.ReFresh_SRES, rooms);
        }

        void Enter(YToken token,SocketModel model ) {
            int id;
            if (model.GetTransModel<int>() ==0) {
                //发送非法消息 area=1
                Send(token, TypeProtocol.Match, 1, MatchProtocol.Enter_SRES);
                //退出
                return;
            }
            id=model.GetTransModel<int>();

            //映射表不存在该房间，退出
            if (!matchRoom.ContainsKey(id)) {
                //发送房间过期消息 area=2
                Send(token, TypeProtocol.Match, 2, MatchProtocol.Enter_SRES);
                return;
            }

            
            MatchRoom room;
            //获取房间失败，退出
            if (!matchRoom.TryGetValue(id, out room)) {
                //发送获取房间失败消息 area=3
                Send(token, TypeProtocol.Match, 3, MatchProtocol.Enter_SRES);
                return; 
            }

            //判断是否满员
            if (room.teamOne.Count + room.teamTwo.Count >= room.count*2) {
                //发送房间满员消息 area=4
                Send(token, TypeProtocol.Match, 4, MatchProtocol.Enter_SRES);
                return;
            }

            //房间存在该连接,退出
            if(room.tokens.Contains(token)){
                //发送你已在房间消息 area=5
                Send(token, TypeProtocol.Match, 5, MatchProtocol.Enter_SRES);
                return;
            }

            //获取连接对应的角色名,若获取失败，退出
            string name = rcache.GetRoleNameByToken(token);
            if (name == null) {
                //发送获取角色信息失败消息 area=6
                Send(token, TypeProtocol.Match, 6, MatchProtocol.Enter_SRES);
                return; 
            }

            //进入房间
            //队伍一人数未满且不大于队伍二人数，进入队伍一
            if (room.teamOne.Count < 5 && room.teamOne.Count <= room.teamTwo.Count)
            {
                room.teamOne.Add(name);
                room.tokens.Add(token);
            }
            else { 
                //否则进入队伍二
                room.teamTwo.Add(name);
                room.tokens.Add(token);
            }

            tokenRoom.Add(token, room);

            //发送房间信息 area=0 进入成功 ,广播消息
            //Send(token, TypeProtocol.Match, 0, MatchProtocol.Enter_SRES, dto);
            Broadcast(room.tokens, TypeProtocol.Match, 0, MatchProtocol.Enter_SRES, GetDTOByRoom(room));
        }

        void Leave(YToken token) {

            //不存在该房间，退出
            if (!tokenRoom.ContainsKey(token)) { Console.WriteLine("exit 1"); return; }

            MatchRoom room=tokenRoom[token];

            //房间不存在该连接，退出
            if (!room.tokens.Contains(token)) { Console.WriteLine("exit 2"); return; }

            //不存在该角色，退出
            string name = rcache.GetRoleNameByToken(token);
            if (name == null) { Console.WriteLine("exit 3"); return; }

            //角色在队伍一
            if (room.teamOne.Contains(name)) {
                Console.WriteLine("remove one"); 
                room.teamOne.Remove(name); 
            }
                //角色在队伍二
            else if (room.teamTwo.Contains(name)) {
                Console.WriteLine("remove two"); 
                room.teamTwo.Remove(name);
            }

            List<YToken> bros = new List<YToken>();
            bros.AddRange(room.tokens.ToArray());
                //room.tokens.ToArray();

            tokenRoom.Remove(token);
            //移除连接
            room.tokens.Remove(token);

            //房间人数为零或者离开的是房主，清空并加入到堆栈中
            if (room.tokens.Count == 0||name.Equals(room.role_name))
            {
                //尝试移除失败，退出
                if (!matchRoom.TryRemove(room.id, out room)) { Console.WriteLine("exit 4"); return; }

                foreach (YToken item in room.tokens)
                {
                    tokenRoom.Remove(item);
                }
                room.Clear();
                roomStack.Push(room);
            }

            //发送离开广播，客户端刷新房间
            Console.WriteLine(room.tokens.Count+" tokens    send "+bros.Count); 
            Broadcast(bros, TypeProtocol.Match, 0, MatchProtocol.Leave_SRES, GetDTOByRoom(room));
            //Send(token, TypeProtocol.Match, 0, MatchProtocol.Leave_SRES, 8);
        }

        /// <summary>
        /// 创建房间
        /// </summary>
        /// 返回area
        /// 正数 表示成功
        /// -1 房间池读取错误
        /// -2 创建房间出错
        /// <param name="token"></param>
        void Create(YToken token) {
            int id=0;

            string name = rcache.GetRoleNameByToken(token);
            if (name == null) { Console.WriteLine("create 1"); return; }

            //从房间池取出房间,或新建房间
            MatchRoom room;
            if (roomStack.Count > 0)
            {
                //if (!roomStack.TryPop(out room)) {
                //    Send(token,-1, MatchProtocol.Create_SRES);
                //    return; 
                //}
                roomStack.TryPop(out room);
            }
            else
            {
                roomIndex.GetAndAdd(ref id);
                room = new MatchRoom();
                room.id = id;
            }

            room.role_name = name;

            room.teamOne.Add(name);
            room.tokens.Add(token);

            //if (!matchRoom.TryAdd(room.id, room)){
            //    room.Clear();
            //    roomStack.Push(room);
            //    Send(token, -2, MatchProtocol.Create_SRES);
            //    return;
            //}
            matchRoom.TryAdd(room.id, room);

            tokenRoom.Add(token, room);
            Send(token,room.id,MatchProtocol.Create_SRES);
            
        }

        void Change(YToken token) {
            //不存在该房间，退出
            if (!tokenRoom.ContainsKey(token)) { Console.WriteLine("change 1"); return; }

            MatchRoom room = tokenRoom[token];

            //房间不存在该连接，退出
            if (!room.tokens.Contains(token)) { Console.WriteLine("change 2"); return; }

            string name = rcache.GetRoleNameByToken(token);

            if (room.teamOne.Contains(name) && room.teamTwo.Count < room.count) {
                room.teamOne.Remove(name);
                room.teamTwo.Add(name);

                Broadcast(room.tokens, TypeProtocol.Match, 0, MatchProtocol.Change_SRES, GetDTOByRoom(room));

                return;
            }

            if (room.teamTwo.Contains(name) && room.teamOne.Count < room.count) {
                room.teamTwo.Remove(name);
                room.teamOne.Add(name);
                Broadcast(room.tokens, TypeProtocol.Match, 0, MatchProtocol.Change_SRES, GetDTOByRoom(room));

                return;
            }

        }

        void Chat(YToken token, SocketModel model) {

            //判断是否存在该房间
            if (!tokenRoom.ContainsKey(token)) { return; }

            MatchRoom room;
            room = tokenRoom[token];

            string name = rcache.GetRoleNameByToken(token);

            string content=name+": "+model.GetTransModel<string>();

            //Console.WriteLine("chat");
            Broadcast(room.tokens, TypeProtocol.Match, 0, MatchProtocol.Chat_SRES, content);
        }

        void Start(YToken token,SocketModel model) {

            if (!tokenRoom.ContainsKey(token)) { return; }

            MatchRoom room;
            room = tokenRoom[token];

            string name = rcache.GetRoleNameByToken(token);
            if (!room.role_name.Equals(name)) { return; }

            Broadcast(room.tokens, MatchProtocol.Start_SRES);

            //todo 通知选择模块创建房间(时间关系没做，直接开始战斗)

            //todo 开始战斗
            FunUtil.createFightDe(room);

            //释放房间
            if (!matchRoom.TryRemove(room.id, out room)) { return; }

            foreach (YToken item in room.tokens)
            {
                tokenRoom.Remove(item);
            }
            
            room.Clear();
            roomStack.Push(room);
        }



        public void OnClientClose(YServer.YToken token, string error)
        {
           //Leave(token
            Leave(token);
        }

        /// <summary>
        /// 根据房间生成dto模型
        /// </summary>
        /// <param name="room"></param>
        /// <returns></returns>
        MatchRoomDTO GetDTOByRoom(MatchRoom room) {
            MatchRoomDTO dto = new MatchRoomDTO(room.id, room.role_name);
            dto.teamOne = room.teamOne.ToArray();
            dto.teamTwo = room.teamTwo.ToArray();
            return dto;
        }

    }
}
